package com.yunda.nebula.gateway.filter;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.gateway.config.LoadBalancerProperties;
import org.springframework.cloud.gateway.filter.LoadBalancerClientFilter;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.http.HttpHeaders;
import org.springframework.web.server.ServerWebExchange;

import java.net.URI;
import java.util.Comparator;
import java.util.List;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;

/**
 * \* User: wei.zhang
 * \* Date: 2019/12/25 16:09
 * \* Description:
 *
 * @author wei.zhang
 * \
 */
@Slf4j
public class IpHashBalancerClientFilter extends LoadBalancerClientFilter {
    public IpHashBalancerClientFilter(LoadBalancerClient loadBalancer, LoadBalancerProperties properties) {
        super(loadBalancer, properties);
    }

    @Autowired
    private DiscoveryClient discoveryClient;

    public boolean isEmpty(String ip){
        if (StringUtils.isEmpty(ip) || "null".equalsIgnoreCase(ip) || "undefined".equalsIgnoreCase(ip)){
            return true;
        }
        return false;
    }

    private String getRemoteIp(ServerWebExchange exchange){
        HttpHeaders httpHeaders = exchange.getRequest().getHeaders();
        /**
         * 获取nginx代理的ip
//         */
        StringBuilder ip =new StringBuilder(30);
        /**
         * 获取测试代理的ip
         */
        if (httpHeaders.containsKey("X_LOCALIP")){
            String localip = httpHeaders.getFirst("X_LOCALIP");
            if (!isEmpty(localip)){
                ip.append(localip);
            }
        }
        if (StringUtils.isNotEmpty(ip.toString())){
            return ip.toString();
        }
        return "";
    }

    @Override
    protected ServiceInstance choose(ServerWebExchange exchange) {
        //这里可以拿到web请求的上下文，可以从header中取出来自己定义的数据。
        //如果第一次请求 是没有LOCALIP的 这时候随机选取
        String ip = getRemoteIp(exchange);
        String path = exchange.getRequest().getURI().getPath();
        log.info("remote ip is {}，访问的地址为 {}",ip,path);
        if (StringUtils.isEmpty(ip)) {
            return super.choose(exchange);
        }else {
            if (this.loadBalancer instanceof RibbonLoadBalancerClient) {
                String serviceId = ((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost();
                List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serviceId);
                if (CollectionUtils.isEmpty(serviceInstances)){
                    return null;
                }
                ServiceInstance serviceInstance = choose(ip,serviceInstances);
                if (serviceInstance != null){
                    log.info("获取服务实例个数为 {} 转发地址为 {} 端口为 {}",serviceInstances.size(),serviceInstance.getHost(),serviceInstance.getPort());
                }
                return serviceInstance;
            }
            return super.choose(exchange);
        }
    }

    /**
     * iphash
     * @param ip
     * @param serviceInstances
     * @return
     */
    public ServiceInstance choose(String ip, List<ServiceInstance> serviceInstances){
        serviceInstances.sort(Comparator.comparing(o -> (o.getHost() + o.getPort())));
        String[] host = ip.split("_");
        if (host == null || host.length == 0 || host.length != 2){
            return null;
        }
        for (ServiceInstance serviceInstance:serviceInstances){
            if (serviceInstance.getHost().equals(host[0]) && serviceInstance.getPort() == Integer.valueOf(host[1])){
                return serviceInstance;
            }
        }
        return null;
    }

}
